package com.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * NIO源生第一个DEMO，NIOserver服务器
 * @author hcf
 * @email hcf0108@163.com
 * @create 2019-03-06 下午 4:32
 **/
public class NIOServer {
    public static final int port =7080;
    private  int flag = 1;
    /** 缓冲区大小 */
    private int blockSize = 4096;
    /** 发送数据缓冲区 */
    private ByteBuffer sendbuffer = ByteBuffer.allocate(blockSize);
    /** 接受数据缓冲区 */
    private  ByteBuffer receivebuffer = ByteBuffer.allocate(blockSize);
    /** 选择器 */
    private Selector selector;

    public static void main(String[] args) throws IOException {
        NIOServer nioServer = new NIOServer(port);
        nioServer.listen();
    }


    /** 初始化
     * @param port ServerSocket绑定的端口号
     * @throws IOException
     */
    public NIOServer(int port) throws IOException {
        //打开服务端的channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //获取socket对象，并设置socket的一下属性
        ServerSocket serverSocket = serverSocketChannel.socket();
        //绑定ip和端口
        serverSocket.bind(new InetSocketAddress(port));
        //打开选择器
        selector = Selector.open();
        //将服务端注册到选择器中,注册打开监听事件
        serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        System.out.println("Server start -> "+ port);
    }

    /** 监听
     * @throws IOException
     */
    public void listen() throws IOException {
        //永远一直监听，而不是监听一次，所以是一个死循环。
        while (true){
            //选择器的事件列表
            selector.select();
            Set<SelectionKey> selectedKeys =  selector.selectedKeys();
            Iterator<SelectionKey>  it = selectedKeys.iterator();
            while (it.hasNext()){
                SelectionKey selectionKey = it.next();
                it.remove();
                //业务逻辑
                handleKey(selectionKey);
            }
        }
    }

    public void handleKey(SelectionKey selectionKey) throws IOException {
        /* 服务端 */
        ServerSocketChannel server= null;
        /* 客户端 */
        SocketChannel client = null;
        /* 接受的内容 */
        String reciveText;
        /* 发送的内容 */
        String sendText;
        /* 标记位 */
        int count = 0;

        if(selectionKey.isAcceptable()){//可接收的事件
            server = (ServerSocketChannel) selectionKey.channel();//可接受的事件的Channel是服务端channel
            client = server.accept();//获取客户端的channel
            client.configureBlocking(false);//客户端不阻塞，阻塞就不是nio
            //以上完成连接
            //读数据，现将客户端注册给selector
            client.register(selector,SelectionKey.OP_READ);
        }

        if (selectionKey.isReadable()){//服务端可接受事件
            //获取channel（客户端）
            client = (SocketChannel) selectionKey.channel();
            count = client.read(receivebuffer);//将数据读到缓冲区内
            if(count>0){
                reciveText = new String(receivebuffer.array(),0,count);//读取服务端接受到客户端发送的数据
                System.out.println("服务端接受到客户端发送的数据:"+reciveText);
                //读完之后，注册写的事件
                client.register(selector,SelectionKey.OP_WRITE);
            }
        }

        if(selectionKey.isWritable()){//服务端可写往客户端事件
            sendbuffer.clear();//清零缓冲区
            client = (SocketChannel) selectionKey.channel();//获取客户端对象
            sendText = "msg send to client: "+ flag++;
            sendbuffer.put(sendText.getBytes());
            sendbuffer.flip();//往缓冲区写入数据

            client.write(sendbuffer);// 发送出去
            System.out.println("服务端发送数据给客户端："+sendText);

        }
    }
}
